package com.jacken.mars.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jacken.mars.commons.constant.CommonConstants;
import com.jacken.mars.entity.SysRole;
import com.jacken.mars.entity.base.BasePageRequest;
import com.jacken.mars.entity.base.PageInfo;
import com.jacken.mars.entity.req.RegisterUserReq;
import com.jacken.mars.entity.req.SmsReq;
import com.jacken.mars.entity.req.SysUserReq;
import com.jacken.mars.entity.vo.SysUserDetailVo;
import com.jacken.mars.entity.vo.SysUserInfoVo;
import com.jacken.mars.entity.vo.SysUserListVo;
import com.jacken.mars.entity.vo.SysUserMenuVo;
import com.jacken.mars.commons.enums.SmsLoginType;
import com.jacken.mars.commons.enums.SmsPlatform;
import com.jacken.mars.commons.enums.SysUserStatus;
import com.jacken.mars.commons.exception.WorkException;
import com.jacken.mars.commons.message.SmsManager;
import com.jacken.mars.service.ISysDeptService;
import com.jacken.mars.service.SysMenuService;
import com.jacken.mars.service.SysRoleService;
import com.jacken.mars.utils.TokenUtils;
import com.jacken.mars.utils.uuid.UUID;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jacken.mars.service.SysUserService;
import com.jacken.mars.mapper.SysUserMapper;
import com.jacken.mars.entity.SysUser;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * 实现层
 *
 * @Author wq
 * @Date 2020-12-15
 **/
@Service
@Transactional(rollbackFor = Exception.class)

public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
    @Resource
    private SmsManager smsManager;

    @Resource
    private SysMenuService sysMenuService;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private ISysDeptService sysDeptService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private TokenUtils tokenUtils;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Value("${mars.token.expire_time}")
    private String expireTime;

    private final String SYS_USER_TOKEN = "user:admin:token:";


    @Override
    public IPage<SysUser> page(BasePageRequest query) {
        IPage<SysUser> page = new Page<>(query.getPageNumber(), query.getPageSize());
        return baseMapper.findByQuery(page, query);
    }


    @Override
    public void sendSmsCode(String mobile) {
        smsManager.sendMessage(new SmsReq().setSmsPlatform(SmsPlatform.ADMIN.getCode()).
                setSmsType(SmsLoginType.ADMIN_LOGIN.getCode()).setMobile(mobile));
    }

    @Override
    public void add(SysUserReq req) {
        SysRole role = sysRoleService.getById(req.getRoleId());
        if (Objects.isNull(role)) {
            throw new WorkException("角色不存在");
        }
        // 手机号排除
        SysUser user = getOne(new QueryWrapper<SysUser>().lambda().select(SysUser::getId)
                .eq(SysUser::getMobile, req.getMobile())
                .last("limit 1"));
        if (Objects.nonNull(user)) {
            throw new WorkException("该电话号码已使用");
        }
        SysUser sysUser = new SysUser();
        sysUser.setAvatar(req.getAvatar());
        sysUser.setDeptId(req.getDeptId());
        sysUser.setCreateTime(new Date());
        sysUser.setUpdateTime(new Date());
        sysUser.setRoleId(req.getRoleId());
        sysUser.setMobile(req.getMobile());
        sysUser.setNickname(req.getNickname());
        sysUser.setDeleted(CommonConstants.ZERO);
        sysUser.setLocked(req.getLocked());
        save(sysUser);
    }

    @Override
    public void delete(Integer id) {
        SysUser sysUser = getById(id);
        if (sysUser == null) {
            throw new WorkException("数据不存在");
        }
        baseMapper.deleteById(id);
    }

    @Override
    public void updateSysUser(SysUserReq req) {
        SysUser user = getById(req.getSysUserId());
        if (Objects.isNull(user)) {
            throw new WorkException("数据不存在");
        }
        SysRole role = sysRoleService.getById(req.getRoleId());
        if (Objects.isNull(role)) {
            throw new WorkException("角色不存在");
        }
        BeanUtils.copyProperties(req, user);
        user.setUpdateTime(new Date());
        updateById(user);
    }

    @Override
    public SysUserDetailVo detail(Integer id) {
        SysUser sysUser = getById(id);
        if (Objects.nonNull(sysUser)) {
            SysUserDetailVo vo = new SysUserDetailVo();
            vo.setDeptId(sysUser.getDeptId());
            vo.setRoleId(sysUser.getRoleId());
            vo.setLocked(sysUser.getLocked());
            vo.setSysUserId(sysUser.getId());
            vo.setNickname(sysUser.getNickname());
            vo.setMobile(sysUser.getMobile());
            return vo;
        }
        return null;
    }


    @Override
    public SysUserInfoVo userInfo(String token) {
        //判断token是否有效
        boolean b = tokenUtils.isTokenExpired(new Date());
        if (b) {
            throw new WorkException("令牌已失效,请重新登录");
        }
        String userInfoStr = tokenUtils.getUserFromToken(token);
        SysUser user = JSONObject.parseObject(userInfoStr, SysUser.class);
        if (Objects.nonNull(user)) {
            SysUserInfoVo sysUserInfoVo = new SysUserInfoVo();
            SysUser sysUser = getById(user.getId());
            sysUserInfoVo.setAvatar(sysUser.getAvatar());
            //角色名称
            String roleTitle = sysRoleService.selectRoleTile(sysUser.getRoleId());
            sysUserInfoVo.setRole(roleTitle);
            //部门名称
            String deptName = sysDeptService.selectDeptName(sysUser.getDeptId());
            sysUserInfoVo.setDeptName(deptName);
            sysUserInfoVo.setUserId(user.getId());
            sysUserInfoVo.setNickname(sysUser.getNickname());
            //根据角色查询菜单
            List<SysUserMenuVo> menuRole = sysMenuService.findMenuRole(sysUser.getRoleId());
            sysUserInfoVo.setMenus(menuRole);
            return sysUserInfoVo;
        }
        return null;
    }

    @Override
    public PageInfo<SysUserListVo> sysUserPage(SysUserReq req) {

        IPage<SysUser> page = new Page<>(req.getPageNumber(), req.getPageSize());
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNoneEmpty(req.getNickname())) {
            wrapper.like(SysUser::getNickname, req.getNickname());
        }
        if (StringUtils.isNoneEmpty(req.getMobile())) {
            wrapper.like(SysUser::getMobile, req.getMobile());
        }
        wrapper.orderByDesc(SysUser::getCreateTime);
        List<SysUserListVo> list = baseMapper.selectPage(page, wrapper).getRecords().stream().map(x -> {
            SysUserListVo vo = new SysUserListVo();
            vo.setSysUserId(x.getId());
            vo.setAvatar(x.getAvatar());
            vo.setMobile(x.getMobile());
            vo.setCreateTime(x.getCreateTime());
            String roleTile = sysRoleService.selectRoleTile(x.getRoleId());
            vo.setRoleTitle(roleTile);
            //部门名称
            String deptName = sysDeptService.selectDeptName(x.getDeptId());
            vo.setDeptName(deptName);
            vo.setNickname(x.getNickname());
            vo.setLocked(x.getLocked());
            return vo;
        }).collect(Collectors.toList());
        return new PageInfo<>(page.getTotal(), list);
    }


    @Override
    public void logout(String token) {
        String userStr = tokenUtils.getUserFromToken(token);
        SysUser sysUser = JSONObject.parseObject(userStr, SysUser.class);
        if (Objects.nonNull(sysUser)) {
            stringRedisTemplate.delete(SYS_USER_TOKEN + sysUser.getId());
        }
    }

    @Override
    public String login(String mobile, String code) {
        SysUser sysUser = baseMapper.selectUserMobile(mobile);
        if (Objects.isNull(sysUser)) {
            throw new WorkException("用户不存在");
        }
        if (SysUserStatus.LOCKED.getCode().equals(sysUser.getLocked())) {
            throw new WorkException("用户不可用,联系管理员");
        }
        //校验短信验证码
        boolean b = checkVerificationCode(mobile, code);
        if (b) {
            String cacheToken = stringRedisTemplate.opsForValue().get(SYS_USER_TOKEN + sysUser.getId());
            if (StringUtils.isEmpty(cacheToken)) {
                String token = tokenUtils.createToken(JSONObject.toJSONString(sysUser));
                //缓存30天
                stringRedisTemplate.opsForValue().set(SYS_USER_TOKEN + sysUser.getId(), token,
                        Long.parseLong(expireTime), TimeUnit.DAYS);
                return token;
            } else {
                return cacheToken;
            }
        }
        return null;
    }

    @Override
    public String v2Login(String mobile, String code, String uuid) {
        SysUser sysUser = sysUserMapper.selectUserByMobile(mobile);
        if (Objects.isNull(sysUser)) {
            //注册
            checkCode(code, uuid);
            //创建用户
            sysUser = createSysUser(mobile);
            //返回token
            String cacheToken = stringRedisTemplate.opsForValue().get(SYS_USER_TOKEN + sysUser.getId());
            if (StringUtils.isEmpty(cacheToken)) {
                String token = tokenUtils.createToken(JSONObject.toJSONString(sysUser));
                //缓存30天
                stringRedisTemplate.opsForValue().set(SYS_USER_TOKEN + sysUser.getId(), token, Long.parseLong(expireTime), TimeUnit.DAYS);
                return token;
            } else {
                return cacheToken;
            }
        } else {
            //登录
            checkCode(code, uuid);
            String token = tokenUtils.createToken(JSONObject.toJSONString(sysUser));
            //缓存30天
            stringRedisTemplate.opsForValue().set(SYS_USER_TOKEN + sysUser.getId(), token, Long.parseLong(expireTime), TimeUnit.DAYS);
            return token;
        }
    }

    /**
     * 创建用户
     *
     * @param mobile
     */
    private SysUser createSysUser(String mobile) {
        SysUser sysUser = new SysUser();
        sysUser.setAvatar(CommonConstants.DEFAULT_AVATAR);
        sysUser.setLocked(CommonConstants.ONE);
        sysUser.setNickname("用户_" + mobile.substring(7));
        sysUser.setCreateTime(new Date());
        sysUser.setDeptId(CommonConstants.ONE);
        sysUser.setDeleted(CommonConstants.ZERO);
        sysUser.setRoleId(CommonConstants.ONE);
        sysUser.setUpdateTime(new Date());
        sysUser.setMobile(mobile);
        sysUserMapper.insert(sysUser);
        return sysUser;

    }

    /**
     * 验证验证码
     *
     * @param code
     * @param uuid
     */
    private void checkCode(String code, String uuid) {
        String verifyKey = CommonConstants.CAPTCHA_CODE_KEY + uuid;
        String captcha = stringRedisTemplate.opsForValue().get(verifyKey);
        stringRedisTemplate.delete(verifyKey);
        if (StringUtils.isEmpty(captcha)) {
            throw new WorkException("验证码已失效");
        }
        if (!code.equalsIgnoreCase(captcha)) {
            throw new WorkException("验证码错误");
        }
    }

    @Override
    public SysUser selectUserByMobile(String mobile) {
        return baseMapper.selectUserMobile(mobile);
    }

    @Override
    public String v3Login(String mobile, String password, String code, String uuid) {
        if (StringUtils.isEmpty(mobile)) {
            throw new WorkException("请输入账号");
        }
        boolean b = checkMobile(mobile);
        if (!b) {
            throw new WorkException("手机号格式不正确");
        }
        if (StringUtils.isEmpty(password)) {
            throw new WorkException("请输入密码");
        }
        SysUser sysUser = sysUserMapper.selectUserByMobile(mobile);
        if (Objects.isNull(sysUser)) {
            throw new WorkException("该账号还未注册,不能登录哦");
        }
        if (sysUser.getLocked().equals(CommonConstants.TWO)) {
            throw new WorkException("该账号已锁定,请联系管理员");
        }
        //验证密码是否正确
        if (!UUID.nameUUIDFromBytes(password.getBytes()).equals(sysUser.getPassword())) {
            throw new WorkException("密码不正确,请重新输入");
        }
        //校验验证码
        checkCode(code, uuid);
        String token = tokenUtils.createToken(JSONObject.toJSONString(sysUser));
        //缓存30天
        stringRedisTemplate.opsForValue().set(SYS_USER_TOKEN + sysUser.getId(), token, Long.parseLong(expireTime), TimeUnit.DAYS);
        return token;
    }

    @Override
    public void register(RegisterUserReq req) {
        SysUser user = baseMapper.selectUserMobile(req.getMobile());
        if (Objects.nonNull(user)) {
            throw new WorkException("该账号已被注册");
        }
        if (!req.getPassword().equals(req.getConfirmPassword())) {
            throw new WorkException("两次输入密码不正确,请重新输入");
        }
        SysUser sysUser = new SysUser();
        sysUser.setAvatar(CommonConstants.DEFAULT_AVATAR);
        sysUser.setLocked(CommonConstants.ONE);
        sysUser.setNickname("用户_" + req.getMobile().substring(7));
        sysUser.setCreateTime(new Date());
        sysUser.setDeptId(CommonConstants.ONE);
        sysUser.setDeleted(CommonConstants.ZERO);
        sysUser.setRoleId(CommonConstants.ONE);
        sysUser.setUpdateTime(new Date());
        sysUser.setMobile(req.getMobile());
        sysUser.setPassword(req.getPassword());
        sysUser.setEmail(req.getEmail());
        sysUser.setConfirmPassword(req.getConfirmPassword());
        sysUserMapper.insert(sysUser);

    }

    /**
     * 手机号正则
     *
     * @param phoneNum
     * @return
     */
    public static boolean checkMobile(String phoneNum) {
        String regex = "^(1[3-9]\\d{9}$)";
        if (phoneNum.length() == 11) {
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(phoneNum);
            if (m.matches()) {
                return true;
            }
        }
        return false;
    }


    /**
     * 校验短信验证码
     *
     * @param mobile mobile
     * @param code   code
     * @return boolean
     */
    private boolean checkVerificationCode(String mobile, String code) {
        return smsManager.checkSmsCode(new SmsReq().setSmsPlatform(SmsPlatform.ADMIN.getCode()).
                setSmsType(SmsLoginType.ADMIN_LOGIN.getCode()).setCode(code).setMobile(mobile));
    }


}